package com.xhl.core.validate.image;

import com.xhl.core.properties.base.SecurityProperties;
import com.xhl.core.validate.base.ValidateCodeGenerator;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.context.request.ServletWebRequest;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;

/**
 * @author 徐宏亮
 * @description 图形验证码生成器，返回 ImageCode
 * @date 2019/3/4 22:42
 */
@Getter
@Setter
@Component("imageValidateCodeGenerator")
public class ImageCodeGenerator implements ValidateCodeGenerator {
    @Autowired
    private SecurityProperties securityProperties;

    /**
     * 创建图形验证码对象
     * 说明：
     *  可配置四个参数，其中 width 和 height 可从请求中设置，
     *  还有长度 length 和过期时间 ExpireIn 在配置类中配置
     * @param request 可以获取请求参数与发送参数
     * @return ImageCode
     */
    @Override
    public ImageCode generate(ServletWebRequest request) {
        // 在内存中创建图象
        // 通过这里可以修改图片大小，可从 url 获取值
        int width = ServletRequestUtils.getIntParameter(request.getRequest(),
                "width", securityProperties.getValidateCode().getImageCode().getWidth());
        int height = ServletRequestUtils.getIntParameter(request.getRequest(),
                "height", securityProperties.getValidateCode().getImageCode().getHeight());
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        // 获取图形上下文
        // g相当于笔
        Graphics g = image.getGraphics();
        //生成随机类
        Random random = new Random();
        // 设定背景色
        g.setColor(getRandColor(200, 250));
        // 画一个实心的长方，作为北京
        g.fillRect(0, 0, width, height);
        //设定字体
        g.setFont(new Font("Times New Roman", Font.ITALIC, 20));
        //画边框
        g.setColor(Color.BLUE);
        g.drawRect(0, 0, width - 1, height - 1);
        // 随机产生155条干扰线，使图象中的认证码不易被其它程序探测到
        g.setColor(getRandColor(160, 200));
        for (int i = 0; i < 155; i++) {
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            int xl = random.nextInt(12);
            int yl = random.nextInt(12);
            g.drawLine(x, y, x + xl, y + yl);
        }

        // 取随机产生的认证码(4位数字)
        StringBuilder sRand = new StringBuilder();
        // 如果要使用中文，必须定义字库，可以使用数组进行定义
        // 这里直接写中文会出乱码，必须将中文转换为unicode编码
        String[] str = {"A", "B", "C", "D", "E", "F", "G", "H", "J", "K",
                "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X",
                "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
                "k", "m", "n", "p", "s", "t", "u", "v", "w", "x", "y", "z",
                "1", "2", "3", "4", "5", "6", "7", "8", "9"};
        for (int i = 0; i < securityProperties.getValidateCode().getImageCode().getLength(); i++) {
            String rand = str[random.nextInt(str.length)];
            sRand.append(rand);
            // 将认证码显示到图象中
            g.setColor(new Color(20 + random.nextInt(110), 20 + random
                    .nextInt(110), 20 + random.nextInt(110)));//调用函数出来的颜色相同，可能是因为种子太接近，所以只能直接生成
            g.drawString(rand, 13 * i + 6, 16);
        }
        // 图象生效
        g.dispose();

        // 生成对象，配置过期时间
        return new ImageCode(image, sRand.toString(), securityProperties.getValidateCode().getImageCode().getExpireIn());
    }

    /**
     * 生成随机背景条纹
     *
     * @param fc
     * @param bc
     * @return
     */
    private Color getRandColor(int fc, int bc) {
        Random random = new Random();
        if (fc > 255) {
            fc = 255;
        }
        if (bc > 255) {
            bc = 255;
        }
        int r = fc + random.nextInt(bc - fc);
        int g = fc + random.nextInt(bc - fc);
        int b = fc + random.nextInt(bc - fc);
        return new Color(r, g, b);
    }
}
